import { WKT, GeoJSON } from 'ol/format'
import _ from 'lodash';
import { Feature } from 'ol';
import { Vector as VectorLayer } from 'ol/layer'
import { Vector as VectorSource } from 'ol/source'
import Style from 'ol/style/Style';
import Stroke from 'ol/style/Stroke';
import Fill from 'ol/style/Fill';
import { Circle, Text as TextStyle } from 'ol/style';
import CircleGeom from 'ol/geom/Circle';
import { transform } from 'ol/proj';
import { LineString, Point } from 'ol/geom';
import { transformExtent } from 'ol/proj'
import Api from '../api';
import ZhfxApi from '../apis/ZhfxApi';
import CztApi from '../apis/CztApi';
import JzzyApi from '../apis/JzzyApi';
import ZdfhApi from '../apis/ZdfhApi';

export const clearHighlight = (map) => {
    const layer = createHighlightLayer(map);
    layer.getSource().clear();
}
export const createHighlightLayer = (map, id) => {
    let highlightLayer = map?.getLayers()?.getArray()?.find(layer => {
        return layer.get('id') === 'highlight-layer'
    });
    if (!highlightLayer) {
        highlightLayer = new VectorLayer({
            id: 'highlight-layer',
            style: new Style({
                fill: new Fill({
                    color: 'rgba(255,0,0,0.2)'
                }),
                stroke: new Stroke({
                    color: 'rgba(0,255,255,1)',
                    width: 3,
                }),
                image: new Circle({
                    fill: new Fill({
                        color: 'rgba(255,0,0,1)'
                    }),
                    radius: 4
                })
            }),
            source: new VectorSource()
        });
        map?.addLayer(highlightLayer);
    }
    return highlightLayer;
}
export const navByWkt = (wkt, map, onlyNav, noClear) => {
    const feature = wktToFeature(wkt);
    const geom = feature.getGeometry();
    if (geom.getType() === 'Point') {
        map.getView().animate({
            center: geom.getCoordinates()
        });
    } else {
        const newGeom = geom.clone()
        newGeom.scale(2, 2)
        map.getView().fit(newGeom, { duration: 1000 });
    }
    if (!onlyNav) {
        const highlightLayer = createHighlightLayer(map);
        !noClear && highlightLayer.getSource().clear();
        highlightLayer.getSource().addFeatures([feature])
    }
}

export const geomToGeoJson = (geom) => {
    return new GeoJSON().writeGeometryObject(geom);
}
export const geoJsonToFeature = (geojson) => {
    return new GeoJSON().readFeature(geojson);
}
export const geomToWkt = (geom) => {
    const wktFormat = new WKT();
    return wktFormat.writeGeometry(geom);
}
export const wktToGeom = (wkt) => {
    const wktFormat = new WKT();
    return wktFormat.readGeometry(wkt);
}
export const wktToFeature = (wkt) => {
    const wktFormat = new WKT();
    return wktFormat.readFeature(wkt);
}
export const dataToFeature = (data) => {
    if (!data?.shap && !data?.geom) {
        return null
    }
    const wktFormat = new WKT();
    const feature = wktFormat.readFeature(data.shap || data.geom);
    _.unset(data, 'shap');
    feature.setProperties(data);
    return feature
}

export const createLayer = (style, features = [], opt = {}) => {
    const source = new VectorSource();
    const layer = new VectorLayer({
        source,
        // renderMode: 'image',
        // renderOrder: null,
        // declutter: true,
        ...opt,
        style: _.isFunction(style) ? style : new Style({
            fill: new Fill({
                color: style?.fill?.color || 'rgba(0,0,0,0.5)'
            }),
            stroke: new Stroke({
                color: style?.stroke?.color || 'rgb(0,0,0)',
                width: style?.stroke?.width || 1,
            }),
            image: new Circle({
                fill: new Fill({
                    color: style?.circle?.fill?.color || 'rgba(0,0,0,0.5)'
                }),
                stroke: new Stroke({
                    color: style?.circle?.stroke?.color || 'rgb(255,0,0)',
                    width: style?.circle?.stroke?.width || 2,
                }),
                radius: 10
            })
        })
    })
    source.addFeatures(features)
    return layer
}

export const drawCircle = (map, wkt, radius, options) => {
    if (radius < 0) {
        radius = 0;
    }
    const { noClear } = options || {}
    let coords = wkt;
    if (!_.isArray(coords)) {
        const geom = wktToGeom(wkt);
        coords = geom.getCoordinates();
    }
    let coords3857 = transform(coords, 'EPSG:4326', 'EPSG:3857');
    const circleGeom = new CircleGeom(coords3857, radius * 1000);
    const newGeom = circleGeom.transform('EPSG:3857', 'EPSG:4326')
    let highlightLayer = createHighlightLayer(map)
    !noClear && highlightLayer.getSource().clear();
    const labelFeature = new Feature({
        geometry: new LineString([coords, [coords[0] + newGeom.getRadius(), coords[1]]]),
    })
    labelFeature.setStyle(new Style({
        text: new TextStyle({
            font: '12px sans-serif',
            text: `半径：${radius}KM`,
            fill: new Fill({
                color: 'rgba(0,255,255,1)',
            }),
            offsetY: -8
        }),
        stroke: new Stroke({
            color: 'rgba(0,255,255,1)',
            width: 3,
        }),
    }))
    highlightLayer.getSource().addFeatures([
        new Feature({
            geometry: newGeom
        }),
        new Feature({
            geometry: new Point(coords)
        }),
        labelFeature
    ])
    return newGeom;
}

export const isIntersects = (geom1, geom2) => {
    if (window.turf) {
        var format = new GeoJSON();
        var g1 = format.writeGeometryObject(geom1);
        var g2 = format.writeGeometryObject(geom2);
        return window.turf.intersect(g1, g2);
    }
}


const generateData = (datas, dl, dlName) => {
    datas.forEach(data => {
        data.dl = dl;
        data.dlName = dlName;
        if (data.children) {
            generateData(data.children, dl, dlName)
        }
    });
    return datas
}
const findByTitle = (title, datas) => {
    for (let i = 0; i < datas.length; i++) {
        const data = datas[i];
        if (data.title === title) {
            return data;
        }
        if (data.children) {
            return findByTitle(title, data.children);
        }

    }
}
let baseLayers;
export const createBaseLayers = (callback) => {
    if (baseLayers) {
        callback?.(baseLayers);
        return;
    }
    Promise.all([Api.getZhfxCategroy(), Api.getCztCategroy(), Api.getJzzyCategroy(), Api.getZdfhCategroy()]).then(([resp1, resp2, resp3, resp4]) => {
        const layerDatas = [{
            title: "灾害风险",
            children: generateData(resp1, 'zhfx', "灾害风险"),
            dl: 'zhfx'
        }, {
            title: "承灾体",
            children: generateData(resp2, 'czt', "承灾体"),
            dl: 'czt'
        }, {
            title: "减灾资源",
            children: generateData(resp3, 'jzzy', "减灾资源"),
            dl: 'jzzy'
        },

            // {
            //     title: "重点防护目标",
            //     children: generateData(resp4, 'zdfh', "重点防护目标"),
            //     dl: 'zdfh'
            // }
        ]
        const layers = [];
        const generate = (datas) => {
            datas.forEach(data => {
                if (data.children) {
                    generate(data.children);
                } else {
                    layers.push(data);
                }
            })
        }
        generate(layerDatas);
        baseLayers = layerDatas.map(layerData => {
            const l = new VectorLayer({
                layerName: layerData.title,
                renderMode: 'image',
                renderOrder: null,
                declutter: true,
                // visible: false,
                style: (feature) => {
                    const lxTitle = feature.get('lxTitle');
                    const targetData = findByTitle(lxTitle, layerData.children);
                    let style;
                    if (targetData?.style) {
                        let styleJson = {};
                        if (targetData.style.fill) {
                            styleJson.fill = new Fill({
                                ...targetData.style.fill
                            });
                        }
                        if (targetData.style.stroke) {
                            styleJson.stroke = new Stroke({
                                ...targetData.style.stroke
                            });
                        }

                        if (targetData.style.circle) {
                            const circle = { ...targetData.style.circle }
                            if (circle.fill) {
                                circle.fill = new Fill({
                                    ...circle.fill
                                })
                            }
                            if (circle.stroke) {
                                circle.stroke = new Stroke({
                                    ...circle.stroke
                                })
                            }
                            styleJson.image = new Circle({
                                ...circle
                            });
                        }
                        style = new Style(styleJson)
                    }
                    return style || new Style({
                        fill: new Fill({
                            color: style?.fill?.color || 'rgba(0,0,0,0.5)'
                        }),
                        stroke: new Stroke({
                            color: style?.stroke?.color || 'rgb(0,0,0)',
                            width: style?.stroke?.width || 1,
                        }),
                        image: new Circle({
                            fill: new Fill({
                                color: style?.circle?.fill?.color || 'rgba(0,0,0,0.5)'
                            }),
                            stroke: new Stroke({
                                color: style?.circle?.stroke?.color || 'rgb(255,0,0)',
                                width: style?.circle?.stroke?.width || 2,
                            }),
                            radius: 10
                        })
                    });
                },
                source: new VectorSource({
                    loader: function (extent, resolution, projection, success, failure) {
                        if (layerData.dl === 'zhfx') {

                            ZhfxApi.list().then(resp => {
                                const features = resp.rows.filter(data => data.geom).map(data => {
                                    const feature = dataToFeature(data);
                                    feature.set('layerName', layerData.title)
                                    feature.set('lxTitle', data.yhlx)
                                    return feature;
                                })
                                // map.getView().fit(features[0].getGeometry())
                                this.addFeatures(features)
                                // success(features);
                            })
                        }
                        else if (layerData.dl === 'czt') {
                            CztApi.list().then(resp => {
                                const features = resp.rows.filter(data => data.geom).map(data => {
                                    const feature = dataToFeature(data);
                                    feature.set('layerName', layerData.title)
                                    feature.set('lxTitle', data.cztxl)
                                    return feature;
                                })
                                // map.getView().fit(features[0].getGeometry())
                                this.addFeatures(features)
                                // success(features);
                            })
                        } else if (layerData.dl === 'jzzy') {

                            JzzyApi.list().then(resp => {
                                const features = resp.rows.filter(data => data.geom).map(data => {
                                    const feature = dataToFeature(data);
                                    feature.set('layerName', layerData.title)
                                    feature.set('lxTitle', data.jzzyxl)
                                    return feature;
                                })
                                // map.getView().fit(features[0].getGeometry())
                                this.addFeatures(features)
                                // success(features);
                            })
                        }
                        // else if (layerInfo.dl === 'zdfh') {

                        //     ZdfhApi.list().then(resp => {
                        //         const features = resp.rows.filter(data => data.geom).map(data => {
                        //             const feature = dataToFeature(data);
                        //             feature.set('layerName', layerInfo.title)
                        //             return feature;
                        //         })
                        //         this.addFeatures(features)
                        //     })
                        // }




                    }
                })
            });
            return l;
        })
        callback?.(baseLayers)
    })
}

export const lengthTo4326 = (length3857) => {
    const epsg3857 = 'EPSG:3857';
    const epsg4326 = 'EPSG:4326';

    // 转换长度值
    var length4326 = transformExtent(
        [0, 0, length3857, 0],  // 在 EPSG:3857 下定义长度范围
        epsg3857,  // 当前投影为 EPSG:3857
        epsg4326  // 目标投影为 EPSG:4326
    )[2];
    return length4326
}

export const animateScatter = ({ point, timeStep, radius, map, currentRadius }) => {
    let scatterLayer = map?.getLayers()?.getArray()?.find(layer => {
        return layer.get('id') === 'scatter-layer'
    });
    if (!scatterLayer) {
        scatterLayer = new VectorLayer({
            source: new VectorSource()
        });
        map.addLayer(scatterLayer)
    }
    const scatterSource = scatterLayer.getSource();

    const style = new Style({
        fill: new Fill({
            color: 'rgba(255,0,0,0.3)'
        }),
        stroke: new Stroke({
            color: 'rgba(255,0,0,1)',
            width: 3
        })
    });
    const newCircle = new CircleGeom(point, lengthTo4326(1));
    const maxCircle = new CircleGeom(point, lengthTo4326(radius));
    maxCircle.scale(2)
    const feature = new Feature({
        geometry: newCircle
    })
    feature.setStyle(style);
    scatterSource.addFeature(feature)
    let currentTime = 0;
    const gapRadius = lengthTo4326((radius / (timeStep * 1000)) * 16)
    const interval = setInterval(() => {
        if (currentTime > timeStep * 1000) {
            newCircle.setRadius(lengthTo4326(1));
            currentTime = 0;
        } else {
            let currentRadius = newCircle.getRadius();
            currentRadius += gapRadius;
            newCircle.setRadius(currentRadius)
        }
        currentTime += 16;
    }, 16)
    map.getView().fit(maxCircle, {
        duration: 500
    })
    return [interval, newCircle];
}